package org.jeecg.modules.login.api;

import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.login.LoginService;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.modules.login.handler.wechat.WeChatPublicHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * [微信公众号] 免密登录
 *
 * @author tianyi.jiang
 * @since 1.2.2
 */
@Slf4j
@AllArgsConstructor
@Controller
@RequestMapping("/sys/wechat/public")
@ConditionalOnExpression("'${basicplatform.login.wechat-public.enable:false}'.equals('true')")
public class WeChatPublicLogin {

    private final WeChatPublicHandler weChatPublicHandler;

    private final LoginService loginService;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 获取二维码地址
     *
     * @return QR Code url
     */
    @ResponseBody
    @GetMapping("/qr")
    public Result<?> qr() {
        String sceneId = UUIDGenerator.generate();
        String qrUrl = weChatPublicHandler.getQr(sceneId);
        Map<String, String> result = new HashMap<String, String>(2) {{
            this.put("sceneId", sceneId);
            this.put("qrUrl", qrUrl);
        }};
        redisUtil.set(sceneId, "", 600L);
        return Result.ok(result);
    }

    /**
     * 微信对接校验
     */
    @GetMapping(value = "/check")
    public void check(HttpServletRequest request, HttpServletResponse response) {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        if (weChatPublicHandler.check(signature, timestamp, nonce)) {
            try {
                PrintWriter print = response.getWriter();
                print.write(echostr);
                print.flush();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 微信推送接收
     */
    @SneakyThrows
    @PostMapping("/check")
    public void login(HttpServletRequest request, HttpServletResponse response) {
        // 获取WxMpXmlMessage
        WxMpXmlMessage wxMpXmlMessage = WxMpXmlMessage.fromXml(request.getInputStream());
        // OpenId
        String fromUserName = wxMpXmlMessage.getFromUser();
        // 消息类型，event
        final String msgType = wxMpXmlMessage.getMsgType();
        // 事件类型
        final String event = wxMpXmlMessage.getEvent();

        String ticket = wxMpXmlMessage.getTicket();
        String sceneStr = "";
        log.info("微信返回验签是：{},{},{}", msgType, event, fromUserName);
        if (WxConsts.XmlMsgType.EVENT.equals(msgType)) {
            if (event.equals(WxConsts.EventType.SUBSCRIBE)) {
                if (ticket != null) {
                    sceneStr = wxMpXmlMessage.getEventKey().replace("qrscene_", "");
                }
            }
            //注：事件类型为SCAN即已关注
            else if (event.equals(WxConsts.EventType.SCAN)) {
                if (ticket != null) {
                    sceneStr = wxMpXmlMessage.getEventKey();
                }
            }
            // 如果sceneStr不为空代表用户已经扫描并且关注了公众号
            if (StringUtils.isNotEmpty(sceneStr)) {
                String openId = request.getParameter("openid");
                log.info("微信推送响应openId:{}", openId);
                // 将微信公众号用户ID缓存到redis中，标记用户已经扫码完成，执行登录逻辑。
                redisUtil.set(sceneStr, openId, 600L);
            }
        }
        try {
            PrintWriter print = response.getWriter();
            print.write("success.");
            print.flush();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    @ResponseBody
    @GetMapping("/auth")
    public Result<?> auth(@RequestParam String sceneId) {
        if (StringUtils.isNotEmpty(sceneId)) {
            Object flag = redisUtil.get(sceneId);
            if (flag != null) {
                String openId = String.valueOf(flag);
                if (StringUtils.isNotEmpty(openId)) {
                    return loginService.auth4WechatPublic(openId);
                }
            }
        }
        return Result.ok(null);
    }
}